{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python 赋值机制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "先看一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 100, 3]\n"
     ]
    }
   ],
   "source": [
    "x = [1, 2, 3]\n",
    "y = x\n",
    "x[1] = 100\n",
    "print y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "改变变量`x`的值，变量`y`的值也随着改变，这与**Python**内部的赋值机制有关。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 简单类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "先来看这一段代码在**Python**中的执行过程。\n",
    "\n",
    "```python\n",
    "x = 500\n",
    "y = x\n",
    "y = 'foo'\n",
    "```\n",
    "\n",
    "- `x = 500`\n",
    "\n",
    "**Python**分配了一个 `PyInt` 大小的内存 `pos1` 用来储存对象 `500` ，然后，Python在命名空间中让变量 `x` 指向了这一块内存，注意，整数是不可变类型，所以这块内存的内容是不可变的。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变)|          `x : pos1`         |\n",
    "\n",
    "- `y = x `\n",
    "\n",
    "**Python**并没有使用新的内存来储存变量 `y` 的值，而是在命名空间中，让变量 `y` 与变量 `x` 指向了同一块内存空间。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变)|`x : pos1`<br> `y : pos1`|\n",
    "\n",
    "- `y = 'foo'`\n",
    "\n",
    "**Python**此时分配一个 `PyStr` 大小的内存 `pos2` 来储存对象 `foo` ，然后改变变量 `y` 所指的对象。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变)<br> `pos2 : PyStr('foo')` (不可变)|`x : pos1`<br>`y : pos2`|\n",
    "\n",
    "对这一过程进行验证，可以使用 `id` 函数。\n",
    "\n",
    "    id(x)\n",
    "\n",
    "返回变量 `x` 的内存地址。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "48220272L"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 500\n",
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "48220272L"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = x\n",
    "id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "也可以使用 `is` 来判断是不是指向同一个事物："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "现在 `y` 指向另一块内存："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "39148320L"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = 'foo'\n",
    "id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**Python**会为每个出现的对象进行赋值，哪怕它们的值是一样的，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "48220296L"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 500\n",
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "48220224L"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = 500\n",
    "id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "不过，为了提高内存利用效率，对于一些简单的对象，如一些数值较小的int对象，**Python**采用了重用对象内存的办法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6579504L"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 2\n",
    "id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6579504L"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = 2\n",
    "id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## 容器类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在来看另一段代码：\n",
    "\n",
    "``` python\n",
    "x = [500, 501, 502]\n",
    "y = x\n",
    "y[1] = 600\n",
    "y = [700, 800]\n",
    "```\n",
    "\n",
    "- `x = [500, 501, 502]`\n",
    "\n",
    "Python为3个PyInt分配内存 `pos1` ， `pos2` ， `pos3` （不可变），然后为列表分配一段内存 `pos4` ，它包含3个位置，分别指向这3个内存，最后再让变量 `x` 指向这个列表。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变) <br> `pos2 : PyInt(501)` (不可变) <br>`pos3 : PyInt(502)` (不可变) <br> `pos4 : PyList(pos1, pos2, pos3)` (可变)|`x : pos4`|\n",
    "\n",
    "- `y = x`\n",
    "\n",
    "并没有创建新的对象，只需要将 `y` 指向 `pos4` 即可。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变) <br> `pos2 : PyInt(501)` (不可变) <br> `pos3 : PyInt(502)` (不可变) <br> `pos4 : PyList(pos1, pos2, pos3)` (可变)|`x : pos4`<br>`y : pos4`|\n",
    "\n",
    "- `y[1] = 600`\n",
    "\n",
    "原来 `y[1]` 这个位置指向的是 `pos2` ，由于不能修改 `pos2` 的值，所以首先为 `600` 分配新内存 `pos5` 。\n",
    "\n",
    "再把 `y[1]` 指向的位置修改为 `pos5` 。此时，由于 `pos2` 位置的对象已经没有用了，**Python**会自动调用垃圾处理机制将它回收。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变) <br> `pos2 :` 垃圾回收 <br> `pos3 : PyInt(502)` (不可变) <br> `pos4 : PyList(pos1, pos5, pos3)` (可变)<br>`pos5 : PyInt(600)` (不可变) |`x : pos4`<br> `y : pos4`|\n",
    "\n",
    "- `y = [700, 800]`\n",
    "\n",
    "首先创建这个列表，然后将变量 `y` 指向它。\n",
    "\n",
    "|内存|命名空间|\n",
    "|---|---|\n",
    "|`pos1 : PyInt(500)` (不可变) <br> `pos3 : PyInt(502)` (不可变) <br>`pos4 : PyList(pos1, pos5, pos3)` (可变)<br>`pos5 : PyInt(600)` (不可变) <br>`pos6 : PyInt(700)` (不可变)<br>`pos7 : PyInt(800)` (不可变)<br>`pos8 : PyList(pos6, pos7)` (可变)|`x : pos4` <br> `y : pos8`|\n",
    "\n",
    "对这一过程进行验证："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "48220224\n",
      "48220248\n",
      "48220200\n",
      "54993032\n"
     ]
    }
   ],
   "source": [
    "x = [500, 501, 502]\n",
    "print id(x[0])\n",
    "print id(x[1])\n",
    "print id(x[2])\n",
    "print id(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "赋值，`id(y)` 与 `id(x)` 相同。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "54993032\n"
     ]
    }
   ],
   "source": [
    "y = x\n",
    "print id(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x is y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改 `y[1]` ，`id(y)` 并不改变。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "54993032\n"
     ]
    }
   ],
   "source": [
    "y[1] = 600\n",
    "print id(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`id(x[1])` 和 `id(y[1])` 的值改变了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "48220272\n",
      "48220272\n"
     ]
    }
   ],
   "source": [
    "print id(x[1])\n",
    "print id(y[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更改 `y` 的值，`id(y)` 的值改变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "54995272\n",
      "54993032\n"
     ]
    }
   ],
   "source": [
    "y = [700, 800]\n",
    "print id(y)\n",
    "print id(x)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
